package com.wlwx.simulator.util;

import com.wlwx.simulator.message.inbound.SubmitInBoundRequest;
import io.netty.channel.ChannelHandlerContext;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;

public class Cache {
    private Map<ChannelHandlerContext, BlockingQueue<SubmitInBoundRequest>> submitReq; // IP -> SubmitRequest
    private Map<ChannelHandlerContext, Map<Long, SubmitInBoundRequest>> waitSubmitMap; // IP -> SubmitRequest

    private static final int CAPACITY = 100000;
    private static volatile Cache instance;
    private Cache() {
        submitReq = new ConcurrentHashMap<>();
        waitSubmitMap = new ConcurrentHashMap<>();
    }

    public static Cache get() {
        if(instance == null) {
            synchronized (Cache.class) {
                if(instance == null) {
                    instance = new Cache();
                }
            }
        }

        return instance;
    }

    public boolean addSubmitRequest(ChannelHandlerContext ctx, SubmitInBoundRequest request) {

        BlockingQueue<SubmitInBoundRequest> blockingQueue = submitReq.get(ctx);

        if(blockingQueue == null) {
            synchronized (submitReq) {
                if(blockingQueue == null) {
                    blockingQueue = new ArrayBlockingQueue<>(CAPACITY);
                    submitReq.put(ctx, blockingQueue);
                }
            }
        }

        return blockingQueue.offer(request);
    }

    public Map<ChannelHandlerContext, BlockingQueue<SubmitInBoundRequest>> getSubmitReq() {
        return submitReq;
    }

    public void setSubmitReq(Map<ChannelHandlerContext, BlockingQueue<SubmitInBoundRequest>> submitReq) {
        this.submitReq = submitReq;
    }

    public Map<ChannelHandlerContext, Map<Long, SubmitInBoundRequest>> getWaitSubmitMap() {
        return waitSubmitMap;
    }

    public void setWaitSubmitMap(Map<ChannelHandlerContext, Map<Long, SubmitInBoundRequest>> waitSubmitMap) {
        this.waitSubmitMap = waitSubmitMap;
    }

    public void addSubmitReqToWaitSubmitMap(ChannelHandlerContext ctx, SubmitInBoundRequest submitInBoundRequest) {
        Map<Long, SubmitInBoundRequest> waitMap = waitSubmitMap.get(ctx);

        if(waitMap == null) {
            synchronized (waitSubmitMap) {
                if(waitMap == null) {
                    waitMap = new HashMap<>();
                    waitSubmitMap.put(ctx, waitMap);
                }
            }
        }

        waitMap.put(submitInBoundRequest.getMsgId(), submitInBoundRequest);
    }

    public void removeWaitSubmitReqByCTX(ChannelHandlerContext ctx, SubmitInBoundRequest submitInBoundRequest) {
        Map<Long, SubmitInBoundRequest> waitMap = waitSubmitMap.get(ctx);
        waitMap.remove(submitInBoundRequest.getMsgId());
    }
}
